import React, { PureComponent } from 'react';
import InputNum from './index';

import './NumInputView.less';

const FILL_ID = 'inpit-fill-height'; // 填充dom ID

export default class extends PureComponent {
    static defaultProps = {
        placeholder: '',
        value: '',
        className: '',
        placeholderClass: '',
        blinkClass: '',
        scrollIntoView: true, // 元素滚动到可视区域
        layerHeight: 300, // 遮罩高度
        disabled: false, // 是否禁用
        onDone: () => {}, // 输入结束回调
        onFocus: () => {}, // 获取焦点
        onBlur: () => {}, // 失去焦点
        onClear: () => {}, // 清空数据
        onChange: v => v, // 监听值变化
        inputNum: {}, // inputNum的props
        clearInput: false, // 清除内容btn
        autoBlur: false, // 自动处理失焦事件
        format: '', // 格式化数据
        maxLength: -1, // 字体长度
        containerSelector: '', // 输入框被键盘遮挡时，需要滚动的容器选择器"#xxxContainer"，默认是滚动window
        isReplace: false,
        cursorPosition: 'left', // 光标位置
    };

    state = {
        showValue: this.props.value || '',
        focus: false,
    };

    componentDidMount() {
        $('body').on('click', this.handleBodyClick);
    }

    componentWillUnmount() {
        $('body').off('click', this.handleBodyClick);
    }

    handleBodyClick = e => {
        if (this.props.autoBlur && !this.$dom.contains(e.target)) {
            this.modal && this.modal.close();
        }
    };

    /**
     * 显示光标
     */
    focus = () => {
        if (this.props.disabled || this.state.focus) {
            return;
        }

        // 需要立即更新状态
        this.props.onFocus();

        this.state.focus = true;
        this.forceUpdate();

        const { layerHeight, scrollIntoView, containerSelector } = this.props;
        if (scrollIntoView) {
            // 页面高度不足以把元素显示在可见区域
            if (containerSelector) {
                const container = $(this.$dom).parents(containerSelector)[0];
                const { innerHeight: windowHeight } = window;
                const bodyHeight = container.scrollHeight;
                // 最小需要滚动距离
                const minHeight = layerHeight - (windowHeight - this.$dom.getBoundingClientRect().bottom);
                const scrollTop = container.scrollTop;
                // 可滚动高度
                const scrollTopAll = bodyHeight - container.offsetHeight;
                if (scrollTopAll - scrollTop < minHeight) {
                    // 填充容器 使容器可滚动
                    const div = document.createElement('div');
                    div.style.height = `${minHeight - (scrollTopAll - scrollTop)}px`;
                    div.id = FILL_ID;
                    container.appendChild(div);
                }
                container.scrollTop = minHeight + scrollTop;
            } else {
                const { innerHeight: windowHeight } = window;
                const bodyHeight = document.body.scrollHeight || document.documentElement.scrollHeight;
                // 最小需要滚动距离
                const minHeight = layerHeight - (windowHeight - this.$dom.getBoundingClientRect().bottom);
                const scrollTop = $(window).scrollTop();
                // 可滚动高度
                const scrollTopAll = bodyHeight - windowHeight;
                if (scrollTopAll - scrollTop < minHeight) {
                    $('body').append(
                        `<div style="height: ${minHeight - (scrollTopAll - scrollTop)}px;" id="${FILL_ID}"></div>`
                    );
                }
                $(window).scrollTop(minHeight + scrollTop);
            }
        }

        const {
            value, inputNum, onDone, clearInput, maxLength, onChange, isReplace
        } = this.props;
        if (inputNum) {
            const handleChange = showValue => {
                inputNum.handleChange && inputNum.handleChange(showValue);
                const realValue = maxLength > 0 ? showValue.slice(0, maxLength) : showValue;
                onChange(realValue);
                this.setState({
                    showValue: realValue,
                });
                // 滚动到最右端
                try {
                    $(this.$dom).scrollLeft(Math.max(this.$dom.scrollWidth - $(this.$dom).width() + 5, 0));
                } catch (e) {
                    // do nothing
                }
            };
            handleChange(value);

            const { layer = true } = inputNum;
            this.modal = WPT.Modal.open(
                <InputNum
                    defaultValue={value}
                    ref={c => {
                        this.inputNum = c;
                    }}
                    {...inputNum}
                    isReplace={isReplace}
                    onChange={handleChange}
                />,
                {
                    animationType: 'dd',
                    position: 'bottom',
                    layerStyle: inputNum.layerStyle || { opacity: '0' },
                    layer: !clearInput && layer,
                    onClose: () => {
                        this.blur();
                        onDone(this.state.showValue);
                    },
                }
            );
        }
    };

    /**
     * 失去光标
     */
    blur = () => {
        this.props.scrollIntoView && $(`#${FILL_ID}`).remove();
        this.setState(
            {
                focus: false,
            },
            this.props.onBlur
        );
    };

    refCon = d => {
        this.$dom = d;
    };

    clearInput = e => {
        e.preventDefault();
        e.stopPropagation();
        this.clearInputNum();
    };

    clearInputNum = () => {
        this.props.onClear && this.props.onClear();
        this.setState({ showValue: '' });
        this.inputNum && this.inputNum.setState({ num: '' });
        this.props.onDone('', 'clear');
    };

    format(str = '') {
        if (typeof this.props.format === 'function') {
            return this.props.format(str);
        }
        if (this.props.format == 'tel') {
            return [str.slice(0, 3), str.slice(3, 7), str.slice(7)].filter(i => i).join('-');
        }
        return str;
    }

    render() {
        const {
            disabled,
            value,
            placeholder,
            placeholderClass,
            ref,
            className,
            inputNum,
            clearInput,
            blinkClass,
            cursorPosition,
            ...otherProps
        } = this.props;
        const { focus, showValue } = this.state;

        let realShowValue = null;
        let usePh = false;
        if (focus && inputNum) {
            if (showValue === '') {
                realShowValue = placeholder;
                usePh = true;
            } else {
                realShowValue = this.format(showValue);
            }
        } else if (value === '') {
            realShowValue = placeholder;
            usePh = true;
        } else {
            realShowValue = this.format(value);
        }
        const CURSOR = (
            <span
                className={`cursor blink ${usePh ? 'usePlaceholder' : ''} ${usePh ? cursorPosition : ''} ${blinkClass
                    || ''}`}
            />
        );

        return (
            <div
                {...otherProps}
                ref={this.refCon}
                className={`inputNumView ${className} ${usePh ? placeholderClass : ''} ${usePh ? 'placeholder' : ''}`}
                onClick={!disabled && this.focus}
            >
                {focus && usePh && CURSOR}
                {realShowValue}
                {focus && !usePh && CURSOR}
                {this.props.children}
                {clearInput && focus && !!showValue && <div className="clearInput" onClick={this.clearInput} />}
            </div>
        );
    }
}
